1 module d_getter;
2 import commons;
3 
4 enum DmdVersion = "2.105.0";
5 enum LdcVersion = "1.36.0-beta1";
6 
7 private string getDmdLink()
8 {
9     import std.system;
10     string link = "https://downloads.dlang.org/releases/2.x/" ~ DmdVersion ~ "/dmd." ~ DmdVersion;
11     return link ~ (os == OS.linux ? ".linux.tar.xz" : os == OS.osx ? ".osx.tar.xz" : ".windows.7z");
12 }
13 private string getDmdDownloadOutputName()
14 {
15     version(Posix) return "dmd-"~DmdVersion~".tar.xz";
16     else return "dmd-"~DmdVersion~".7z";
17 }
18 
19 
20 private string getLdcLink()
21 {
22     string baseDownloadLink = "https://github.com/ldc-developers/ldc/releases/download/";
23     baseDownloadLink~= "v"~LdcVersion;
24     baseDownloadLink~= "/ldc2-"~LdcVersion~"-";
25     version(Windows)
26         baseDownloadLink~= "windows-x64.7z";
27     else version(OSX)
28         baseDownloadLink~= "osx-universal.tar.xz";
29     else version(linux)
30         baseDownloadLink~= "linux-x86_64.tar.xz";
31     else assert(false, "D is not supported in your system.");
32     return baseDownloadLink;
33 }
34 
35 private string getOutputPath()
36 {
37     string outputPath = buildNormalizedPath(std.file.getcwd(), "D");
38     string fileName = "ldc2-"~LdcVersion~"-";
39     version(Windows) fileName~= "windows-x64";
40     else version(linux) fileName~= "linux-x86_64";
41     else version(OSX) fileName~= "osx-universal";
42     else assert(false, "Not implemented for your system.");
43     return buildNormalizedPath(outputPath, fileName);
44 }
45 private string getDmdOutputPath()
46 {
47     string outputPath = buildNormalizedPath(std.file.getcwd(), "D");
48     string fileName = "dmd-"~DmdVersion~"-";
49     version(Windows) fileName~= "windows-x64";
50     else version(linux) fileName~= "linux-x86_64";
51     else version(OSX) fileName~= "osx-universal";
52     else assert(false, "Not implemented for your system.");
53     return buildNormalizedPath(outputPath, fileName);
54 }
55 
56 private string getLdcDownloadOutputName()
57 {
58     static string fileName;
59     if(!fileName)
60     {
61         fileName = "ldc2-"~LdcVersion~"-";
62         version(Windows) fileName~= "windows-x64.7z";
63         else version(linux) fileName~= "linux-x86_64.tar.xz";
64         else version(OSX) fileName~= "osx-universal.tar.xz";
65         else assert(false, "System not supported.");
66     }
67     return fileName;
68 }
69 
70 
71 /** 
72  * Must check if ~/.ldc2.conf (%APPDATA%\.ldc\ldc2.conf) exists and then ignore it.
73  * This is a fix since Hipreme Engine should contain the entire build command and make it
74  * predictable.
75  *  Here, it uses the 2nd ldc2.conf, so, one is still able to tweak although not recommended
76  * https://wiki.dlang.org/Using_LDC - Next to ldc2 executable.
77  */
78 private void overrideLdcConf(ref Terminal t)
79 {
80     static import std.file;
81     string ldc2Conf = buildNormalizedPath(getOutputPath(), "etc", "ldc2.conf");
82     t.writelnHighlighted("Overriding ldc2.conf to use one next to ldc executable.");
83     std.file.copy(ldc2Conf, buildNormalizedPath(getOutputPath(), "bin", "ldc2.conf"));
84 }
85 
86 enum wontAffectMessage = "\n\tThis compiler version is installed locally and won't affect your system D installation.";
87 
88 bool installD(ref Terminal t, ref RealTimeConsoleInput input)
89 {
90     bool existsDmd = ("dmdPath" in configs) !is null;
91     bool existsLdc = ("ldcPath" in configs) !is null;
92     bool isDmdExpectedVersion = existsDmd && configs["dmdVersion"].str == DmdVersion;
93     bool isLdcExpectedVersion = existsLdc && configs["ldcVersion"].str == LdcVersion;
94     
95     if(!isLdcExpectedVersion)
96     {
97         if(!existsLdc)
98             t.writelnHighlighted("No ldcVersion specified, your HipremeEngine will attempt to install locally LDC2 " ~LdcVersion ~ 
99             wontAffectMessage);
100         else
101             t.writelnError("Different LDC Version. HipremeEngine will attempt to install locally LDC2 " ~LdcVersion);
102         t.flush;
103         if(!installFileTo("Download D cross compiler LDC2 "~LdcVersion, getLdcLink,
104         getLdcDownloadOutputName, buildNormalizedPath(std.file.getcwd, "D"), t, input))
105         {
106             t.writelnError("Install failed");
107             return false;
108         }
109         t.writeln("Installed.");
110         auto binPath = buildNormalizedPath(getOutputPath, "bin");
111         makeFileExecutable(buildNormalizedPath(binPath, "rdmd"));
112         makeFileExecutable(buildNormalizedPath(binPath, "ldc2"));
113         makeFileExecutable(buildNormalizedPath(binPath, "ldmd2"));
114         makeFileExecutable(buildNormalizedPath(binPath, "dub"));
115         overrideLdcConf(t);
116 
117         string rdmd = buildNormalizedPath(binPath, "rdmd");
118         version(Windows) rdmd = rdmd.setExtension("exe");
119         configs["ldcVersion"] = LdcVersion;
120         configs["ldcPath"] = getOutputPath;
121         configs["rdmdPath"] = rdmd;
122         configs["dubPath"] = binPath;
123         updateConfigFile();
124     }
125     if(!isDmdExpectedVersion)
126     {
127         if(!existsDmd)
128             t.writelnHighlighted("No dmdVersion specified, your HipremeEngine will attempt to install locally DMD " ~DmdVersion ~
129             wontAffectMessage);
130         else
131             t.writelnError("Different DMD Version. HipremeEngine will attempt to install locally DMD " ~DmdVersion);
132         t.flush;
133         if(!installFileTo("Download D fast iteration compiler DMD "~DmdVersion, getDmdLink,
134         getDmdDownloadOutputName, buildNormalizedPath(std.file.getcwd, "D"), t, input))
135         {
136             t.writelnError("Install failed");
137             t.flush;
138             return false;
139         }
140         import std.system;
141 
142         string sys;
143         string bin = "bin";
144         switch(os) with(OS)
145         {
146             case osx: sys = "osx"; break;
147             case win32, win64: sys = "windows"; break;
148             case linux: sys = "linux"; bin = "bin64"; break;
149             default: assert(false, "System not supported.");
150         }
151         string binPath = buildNormalizedPath(getDmdOutputPath, "dmd2", sys, bin);
152         makeFileExecutable(buildNormalizedPath(binPath, "dmd"));
153         makeFileExecutable(buildNormalizedPath(binPath, "dub"));
154         makeFileExecutable(buildNormalizedPath(binPath, "rdmd"));
155 
156         configs["dmdVersion"] = DmdVersion;
157         configs["dmdPath"] = binPath;
158         updateConfigFile();
159     }
160 
161     return true;
162 }
163 
164 
165 bool setupD(ref Terminal t, ref RealTimeConsoleInput input)
166 {
167     if(!installD(t, input))
168     {
169         t.writelnError("Could not setup D. Aborting process");
170         return false;
171     }
172     string concatPath = ":";
173     version(Windows) concatPath = ";";
174 
175     import std.array:join;
176     environment["PATH"] = join([
177         configs["dmdPath"].str,
178         buildNormalizedPath(configs["ldcPath"].str, "bin"),
179         environment["PATH"]
180     ], concatPath);
181 
182     return true;
183 }